﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Brain.IO
{
    public class BinaryFile
    {
        public BinaryFileData[] Files { get; set; }

        public BinaryFileData GetFileByName(string name, bool caseSensitive)
        {
            string lowerName = name.ToLower();

            for (int i = 0; i < Files.Length; i++)
            {
                BinaryFileData file = Files[i];
                if (caseSensitive)
                {
                    if (file.FileName.ToLower() == lowerName)
                    {
                        return file;
                    }
                }
                else
                {
                    if (file.FileName == name)
                    {
                        return file;
                    }
                }
            }
            return null;
        }

        public void Read(Stream stream)
        {
            using (BinaryReader reader = new BinaryReader(stream))
            {
                string header = reader.ReadString();

                if (header == "BJB")
                {
                    // proceed
                    float version = reader.ReadSingle();

                    int files = reader.ReadInt32();
                    Files = new BinaryFileData[files];
                    for (int i = 0; i < files; i++)
                    {
                        string fileName = reader.ReadString();

                        BinaryFileData file = new BinaryFileData();
                        file.FileName = fileName;

                        int size = reader.ReadInt32();
                        file.Data = reader.ReadBytes(size);

                        Files[i] = file;
                    }
                }
                else
                {
                    throw new Exception("Input file is not in Binary Join Brain format");
                }
            }
        }

        public void Write(Stream stream)
        {
            using (BinaryWriter writer = new BinaryWriter(stream))
            {
                writer.Write("BJB");
                writer.Write(0.1f);

                writer.Write(Files.Length);
                for (int i = 0; i < Files.Length; i++)
                {
                    BinaryFileData file = Files[i];

                    writer.Write(file.FileName);
                    writer.Write(file.Data.Length);
                    writer.Write(file.Data);
                }
            }
        }

        public static BinaryFile Join(string dir, Stream File)
        {
            return Join(new DirectoryInfo(dir), File);
        }
        public static BinaryFile Join(DirectoryInfo dir, Stream File)
        {
            if (!dir.Exists)
            {
                throw new DirectoryNotFoundException("Directory " + dir.FullName + " not found by System!");
            }

            FileInfo[] files = dir.GetFiles();

            return Join(files, File);
        }
        public static BinaryFile Join(FileInfo[] files, Stream File)
        {
            BinaryFileData[] fileData = new BinaryFileData[files.Length];

            for (int i = 0; i < files.Length; i++)
            {
                FileInfo file = files[i];

                BinaryFileData data = new BinaryFileData(file);
                fileData[i] = data;
            }

            BinaryFile join = new BinaryFile();
            join.Files = fileData;

            join.Write(File);


            return join;
        }

        public static BinaryFile Separate(Stream File, string dir)
        {
            return Separate(File, new DirectoryInfo(dir));
        }


        public static BinaryFile Separate(Stream File, DirectoryInfo dir)
        {
            if (!dir.Exists)
            {
                throw new DirectoryNotFoundException("Directory " + dir.FullName + " not found by System!");
            }

            BinaryFile join = new BinaryFile();
            join.Read(File);

            for (int i = 0; i < join.Files.Length; i++)
            {
                BinaryFileData data = join.Files[i];

                string final = Path.Combine(dir.FullName, data.FileName);
                data.FileName = final;
                using (FileStream stream = new FileStream(final, FileMode.Create))
                {
                    stream.Write(data.Data, 0, data.Data.Length);
                }
            }

            return join;
        }
    }
}
